package com.example.zdxk.netty;


import com.example.zdxk.Decoder.Message;
import com.example.zdxk.Decoder.NewsDecoder;
import com.example.zdxk.entity.Setting;
import com.example.zdxk.entity.Term;
import com.example.zdxk.service.SettingService;
import com.example.zdxk.service.TermService;
import com.example.zdxk.util.DateUtils;
import com.example.zdxk.util.FormatUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.SocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.xml.bind.DatatypeConverter;

import java.util.List;

import static java.lang.System.out;


/*
    接收消息并根据消息所属协议解析并响应
 */
@Component

public class TcpInboundHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    private SettingService settingService;
    @Autowired
    private TermService termService;
    private RestTemplate restTemplate = new RestTemplate();
    private String imei;

    private static TcpInboundHandler tcpInboundHandler;

    //该注解会在项目启动的时候执行该方法，即spring容器初始化的时候执行，它与构造函数及@Autowired的执行顺序为：
    // 构造函数 >> @Autowired >> @PostConstruct
    @PostConstruct
    public void init(){
        tcpInboundHandler = this;
    }

    /**
     * 建立连接
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //String uuid = ctx.channel().id().asLongText();
        //CurrentChannelService.addChannel(uuid, (SocketChannel) ctx.channel());
        //System.out.println("a new connect come in: " + uuid);


        //String publicKeyString = tcpInboundHandler.suppliersService.getPublicKeyBySsid("admin");


        //logger.info("TEST: "+publicKeyString);
        System.out.println("channelActive: "+((SocketChannel) ctx.channel()).remoteAddress().toString());

        ctx.fireChannelActive();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
    ByteBuf result = (ByteBuf) msg;
    byte[] resultByte = new byte[result.readableBytes()];
    // msg中存储的是ByteBuf类型的数据，把数据读取到byte[]中
    result.readBytes(resultByte);

    String resultHex = DatatypeConverter.printHexBinary(resultByte);        //将一个byte[]数组编码成一个String类型，转义

    //int type = ProtocolSelector.identify(resultHex,new String(resultByte));     //协议识别
    //临时记录收到的数据
    System.out.println(DateUtils.getTime()+'\n'+"HEX :"+ resultHex);        //将字节数组对应的二进制化为对应的16进制字符串
    System.out.println("STR :"+new String(resultByte)+"\n");                //将字节数组对应的二进制化为对应的ASC码，再化为对应的字符串


    //----------------------------解析并返回应答消息------------------
    byte[] responseBytes = null;
    byte[] settingBytes = null;
    int len = resultByte.length;
    byte[] temp = new byte[len-3];
    System.arraycopy(resultByte,0,temp,0,len-3);
    byte check = FormatUtil.getXor(temp);

    if(check == resultByte[len-3]){                             //判断校验码是否有误
        NewsDecoder newsDecoder = new NewsDecoder();
        newsDecoder.decode(resultByte);

        this.imei = newsDecoder.getImei();                      //设置保存Imei
        if(CurrentChannelService.getChannel(imei)==null){

            // tcpInboundHandler.deviceInfoService.s(imei,"1");
            CurrentChannelService.addChannel(imei, (SocketChannel) ctx.channel());
            System.out.println("a new connect come in: " + imei);
        }

        //resultBytes为00应该不写出
        responseBytes = newsDecoder.getResponse();              //经过解析器，得到应答数组
//        responseBytes = new byte[]{(byte)0x00, (byte)0x11};
        String t = DatatypeConverter.printHexBinary(responseBytes);
        System.out.println("应答消息:"+ t + "\n");

        //如果有主动发送的请求
        List<Setting> settingList = tcpInboundHandler.settingService.getSettingByImei(imei);
        if(settingList.size() != 0){
            Setting setting = settingList.get(0);

            //将设置内容转换成协议报文
            Message message = new Message();
            String setting_imei_str = setting.getSetting().substring(0, 15);
            byte[] setting_imei_byte = setting_imei_str.getBytes();                 //将设置内容中的imei字符串化为对应的字节数组
            String content1 = DatatypeConverter.printHexBinary(setting_imei_byte);
            String content2 = setting.getSetting().substring(15, setting.getSetting().length());
            byte[] content = FormatUtil.hexStringToBytes(content1+content2);        //将转化后的字符串重新组装
//            byte[] content = setting.getSetting().getBytes();

            byte[] meg_id = FormatUtil.hexStringToBytes(FormatUtil.reverse(FormatUtil.hexStringToBytes(setting.getMeg_id())));// 消息ID   IMEI15位，不是双数
            settingBytes = message.toData(FormatUtil.hexStringToBytes(imei), meg_id, content);


            //将应答消息与设置消息拼接
            byte[] response = new byte[responseBytes.length + settingBytes.length];
            System.arraycopy(responseBytes, 0, response, 0, responseBytes.length);
            System.arraycopy(settingBytes, 0, response, responseBytes.length, settingBytes.length);
            responseBytes = response;
            System.out.println("设置消息:"+DatatypeConverter.printHexBinary(settingBytes));
            System.out.println("合并的消息:"+DatatypeConverter.printHexBinary(responseBytes));

            //更新数据库
            setting.setConfirm("yes");
            setting.setConfirmTime(DateUtils.getTime());
            if(setting.getMeg_id().equals("8013")){         //定位间隔
                Term term = tcpInboundHandler.termService.getTerminfoByImei(imei);
                term.setupload_intervel(Integer.valueOf(content2));
                tcpInboundHandler.termService.update(term);
            }

            tcpInboundHandler.settingService.updateAfterConfirm(setting);
        }


//        for(int i=0; i<3; i++){
//            ByteBuf encoded = ctx.alloc().buffer(responseBytes.length);         //写出
//            encoded.writeBytes(responseBytes);
//            ctx.write(encoded);
//            ctx.flush();
//            Thread.sleep(2000);
//            System.out.println("------------------------");
//        }


        ByteBuf encoded = ctx.alloc().buffer(responseBytes.length);         //写出
        encoded.writeBytes(responseBytes);
        ctx.write(encoded);
        ctx.flush();
        System.out.println("------------------------");


    }else System.out.println("校验码不一致！");

    // 释放资源
    result.release();


}catch (Exception e)
{
    e.printStackTrace();
}
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);

    }

    /**
     * 读完
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // TODO Auto-generated method stub
        //System.out.println("channelReadComplete: "+((SocketChannel) ctx.channel()).remoteAddress().toString());
       // System.out.println(" ");
        super.channelReadComplete(ctx);
        ctx.flush();
        //ctx.close();

    }

    /**
     * 断开连接后移除Channel
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {

        super.channelUnregistered(ctx);
        if(this.imei!=null){

            CurrentChannelService.removeChannel(imei);
            System.out.println(DateUtils.getTime());
            out.println("disconnect : " + imei+"\n"+"\n");

        }
        System.out.println("channelUnregistered"+((SocketChannel) ctx.channel()).remoteAddress().toString());
        System.out.println(" ");
    }

    /*
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
    */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //super.exceptionCaught(ctx, cause);
        Channel channel = ctx.channel();
        //……
        if(channel.isActive())ctx.close();
    }


}